fix(Android): icons are not showing on older Android versions#6998
fix(Android): icons are not showing on older Android versions#6998
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAppContainer now loads a custom font via expo-font's useFonts, tracks font load success/error, and only renders once both Changes
Sequence Diagram(s)sequenceDiagram
participant App as AppContainer
participant Root as RootState
participant Font as ExpoFontLoader
participant Log as Logger
App->>Root: read `root` readiness
App->>Font: call useFonts(load custom font)
Font-->>App: fontsLoaded OR fontError
alt fontError
App->>Log: log font error
end
App->>App: render only if (root && (fontsLoaded || fontError))
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/AppContainer.tsx (2)
51-53: Consider handling the font-loading wait withSplashScreento prevent a blank-screen flash.With the corrected guard (
|| !root), the component returnsnullduring both font loading and root initialization. This can produce a visible blank screen. Theexpo-splash-screenlibrary provides aSplashScreencomponent that you can use to prevent rendering the app until the font is loaded and ready. PairingSplashScreen.preventAutoHideAsync()at the module level andSplashScreen.hideAsync()onceloaded || fontErrorwould give a smoother experience on slow devices where this font load is most likely to be perceptible.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/AppContainer.tsx` around lines 51 - 53, Change the current guard that returns null during font/root init to use the Expo SplashScreen flow: call SplashScreen.preventAutoHideAsync() at module load, keep rendering until the app is ready, and when either loaded || fontError || root is truthy call SplashScreen.hideAsync() before returning the app UI; update references in AppContainer.tsx around the loaded, fontError and root checks to stop returning null directly and instead hide the splash once ready. Ensure you import expo-splash-screen and only call hideAsync once (and handle errors) so the splash prevents the blank-screen flash during font loading.
47-49: Font loading should be hoisted to the app entry point, not placed inside the navigation container component.Expo recommends mapping font files using the
useFontshook in a top-level component such as the root layout file. Placing it here means font loading won't begin until this connected component mounts (after Redux store setup and initial render), adding unnecessary latency. A font loading failure or slow load will block the entire navigation stack.For Android/iOS specifically, there are two ways to add fonts: using the expo-font config plugin (recommended for Android and iOS) or loading them at runtime. On Android and iOS, the plugin allows you to embed font files at build time, which is more efficient than
useFontsorloadAsync. Since the issue is specifically about older Android, the config plugin would be the more robust long-term fix.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/AppContainer.tsx` around lines 47 - 49, The useFonts call inside AppContainer should be removed and font loading hoisted to the app entry point (e.g., App.tsx / root layout) so fonts load before the navigation stack mounts; locate and delete the useFonts invocation in AppContainer and instead load the same './static/fonts/custom.ttf' at app startup (using useFonts in the root component or, for Android/iOS, configure the expo-font config plugin to embed the font at build time), and update AppContainer to assume fonts are already available.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
app/static/fonts/custom.ttfis excluded by!**/*.ttf
📒 Files selected for processing (1)
app/AppContainer.tsx
🔇 Additional comments (1)
app/AppContainer.tsx (1)
47-49: No action needed. The font key'custom'inuseFontscorrectly matches the fontFamily name used bycreateIconSetFromIcoMoonin the CustomIcon component. Line 10 ofapp/containers/CustomIcon/index.tsxexplicitly creates the icon set withcreateIconSetFromIcoMoon(icoMoonConfig, 'custom', 'custom.ttf'), where the second parameter specifies the fontFamily as'custom'. This matches the key in AppContainer.tsx, so icons will render correctly.Likely an incorrect or invalid review comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/AppContainer.tsx`:
- Around line 47-53: The early-return guard in AppContainer is wrong: capture
the second return value from useFonts (error) instead of discarding it, and
change the condition so the component returns null when fonts aren't ready or
root is falsy. Concretely, update the useFonts call to const [loaded, error] =
useFonts(...) and replace the if check with the idiomatic Expo pattern combined
with the root invariant (i.e., return null when fonts are still loading without
an error OR when root is falsy) so that the component only renders when fonts
are loaded (or errored) and root is truthy; reference useFonts, loaded, error,
and root to find the relevant lines.
---
Nitpick comments:
In `@app/AppContainer.tsx`:
- Around line 51-53: Change the current guard that returns null during font/root
init to use the Expo SplashScreen flow: call SplashScreen.preventAutoHideAsync()
at module load, keep rendering until the app is ready, and when either loaded ||
fontError || root is truthy call SplashScreen.hideAsync() before returning the
app UI; update references in AppContainer.tsx around the loaded, fontError and
root checks to stop returning null directly and instead hide the splash once
ready. Ensure you import expo-splash-screen and only call hideAsync once (and
handle errors) so the splash prevents the blank-screen flash during font
loading.
- Around line 47-49: The useFonts call inside AppContainer should be removed and
font loading hoisted to the app entry point (e.g., App.tsx / root layout) so
fonts load before the navigation stack mounts; locate and delete the useFonts
invocation in AppContainer and instead load the same './static/fonts/custom.ttf'
at app startup (using useFonts in the root component or, for Android/iOS,
configure the expo-font config plugin to embed the font at build time), and
update AppContainer to assume fonts are already available.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/AppContainer.tsx (1)
47-51:fontErroris silently swallowed — consider logging it for diagnostics.When
fontErroris non-null the app falls back to rendering without the custom font, which is the right behaviour, but nothing records that the failure happened. On the exact devices this PR targets (older Android), a future regression would be completely invisible.🔍 Suggested observability improvement
const [loaded, fontError] = useFonts({ custom: require('./static/fonts/custom.ttf') }); + + if (fontError) { + console.warn('[AppContainer] Custom font failed to load:', fontError); + // or log to your error-reporting service, e.g. logEvent(...) + } if ((!loaded && !fontError) || !root) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/AppContainer.tsx` around lines 47 - 51, When useFonts returns a non-null fontError in AppContainer.tsx, log the error for diagnostics without changing the fallback behavior; add a single log (e.g., console.error or your app logger) that runs when fontError is truthy (reference useFonts and the fontError variable) and include a clear message like "Failed to load custom font" plus the error object so older Android font failures are recorded. Place the log right before the existing early-return/render fallback that checks "if ((!loaded && !fontError) || !root)" so behavior stays identical but the failure is observable.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/AppContainer.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ESLint and Test / run-eslint-and-test
- GitHub Check: format
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@app/AppContainer.tsx`:
- Around line 47-53: Previously the app could hang waiting for fonts because
fontError wasn't captured and the render guard was incorrect; ensure the
useFonts hook destructures the error (fontError) and that the render guard uses
"if ((!loaded && !fontError) || !root) return null;" so a font load failure
unblocks rendering while still waiting when fonts are loading and root is not
ready; verify these exact symbols (useFonts, fontError, loaded, root) are used
in AppContainer.tsx.
---
Nitpick comments:
In `@app/AppContainer.tsx`:
- Around line 47-51: When useFonts returns a non-null fontError in
AppContainer.tsx, log the error for diagnostics without changing the fallback
behavior; add a single log (e.g., console.error or your app logger) that runs
when fontError is truthy (reference useFonts and the fontError variable) and
include a clear message like "Failed to load custom font" plus the error object
so older Android font failures are recorded. Place the log right before the
existing early-return/render fallback that checks "if ((!loaded && !fontError)
|| !root)" so behavior stays identical but the failure is observable.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/AppContainer.tsx (1)
51-53: Move font error logging into auseEffectto avoid side effects during render.
log(fontError)runs on every re-render when the error is set (e.g., whenrootorisMasterDetailchanges via Redux). Render should be pure — side effects belong inuseEffect. This also prevents duplicate logs in React 19 Strict Mode's double-render.♻️ Proposed fix
+ useEffect(() => { + if (fontError) { + log(fontError); + } + }, [fontError]); + - if (fontError) { - log(fontError); - } - if ((!loaded && !fontError) || !root) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/AppContainer.tsx` around lines 51 - 53, The font error logging is causing a render-side effect — move the log(fontError) call out of the render body of the AppContainer component into a useEffect that runs only when fontError changes; add import { useEffect } from React if missing, create useEffect(() => { if (fontError) log(fontError); }, [fontError]) so logging happens only once per error and avoids duplicate logs in Strict Mode and other re-renders.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/AppContainer.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ESLint and Test / run-eslint-and-test
- GitHub Check: format
🔇 Additional comments (1)
app/AppContainer.tsx (1)
5-5: LGTM!New imports are clean and both
useFontsandlogare used in the component body.Also applies to: 20-20
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@app/AppContainer.tsx`:
- Around line 55-57: The existing guard in AppContainer—if ((!loaded &&
!fontError) || !root) return null;—correctly prevents render until fonts are
loaded (or errored) and root exists; leave this condition as-is in the
AppContainer component to preserve the original root invariant and the idiomatic
Expo useFonts behavior.
---
Nitpick comments:
In `@app/AppContainer.tsx`:
- Around line 51-53: The font error logging is causing a render-side effect —
move the log(fontError) call out of the render body of the AppContainer
component into a useEffect that runs only when fontError changes; add import {
useEffect } from React if missing, create useEffect(() => { if (fontError)
log(fontError); }, [fontError]) so logging happens only once per error and
avoids duplicate logs in Strict Mode and other re-renders.
|
Android Build Available Rocket.Chat Experimental 4.70.0.108296 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNTMqDGL0GnKqGw-T_902u6jPnseCfI0l_IDq-pqmNPwnIA7LGrUQ15MCUvja8qFKqiiLwQAdt2Gbkyo3tRq |
There was a problem hiding this comment.
Pull request overview
This PR addresses missing vector icons on older Android versions by ensuring the custom icon font is bundled and loaded before the app UI renders.
Changes:
- Added the custom icon font file (
custom.ttf) to the app’s static assets. - Preloads the custom font at app startup using
expo-font’suseFonts, gating initial render until the font is ready (or a load error occurs). - Updated logging import to allow reporting font-load failures.
Reviewed changes
Copilot reviewed 1 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| app/static/fonts/custom.ttf | Adds the bundled custom icon font used by the IcoMoon icon set. |
| app/AppContainer.tsx | Preloads the custom font via useFonts and delays initial render until fonts are loaded. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/AppContainer.tsx (1)
51-55: Consider user-visible fallback when font loading fails.When
fontErroris truthy, the app proceeds to render but the custom font won't be loaded, meaning icons will still be missing. The error is logged, but users on affected devices will see the broken icon state.Consider whether to:
- Display a fallback UI or error message to users
- Retry font loading
- Accept this as acceptable degradation (log-only is sufficient)
If option 3 is intentional, this is fine as-is.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/AppContainer.tsx` around lines 51 - 55, The useEffect watching fontError currently only calls log(fontError) and leaves users seeing broken icons; update the handling for fontError (in the useEffect and related render logic in AppContainer and any font-loading functions) to provide a user-visible fallback: either set a new state like useFallbackIcons (toggled when fontError is truthy) and render system-font/icon fallbacks or a small non-blocking banner/error message, or implement a retry attempt (call your font load function with exponential backoff from the useEffect) and fall back to system fonts if retries fail; pick one approach, wire the state into the render path so icons/fonts degrade gracefully instead of silently logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@app/AppContainer.tsx`:
- Around line 51-55: The useEffect watching fontError currently only calls
log(fontError) and leaves users seeing broken icons; update the handling for
fontError (in the useEffect and related render logic in AppContainer and any
font-loading functions) to provide a user-visible fallback: either set a new
state like useFallbackIcons (toggled when fontError is truthy) and render
system-font/icon fallbacks or a small non-blocking banner/error message, or
implement a retry attempt (call your font load function with exponential backoff
from the useEffect) and fall back to system fonts if retries fail; pick one
approach, wire the state into the render path so icons/fonts degrade gracefully
instead of silently logging.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 523c4257-c54d-4039-99a7-d3e5cbf6d49c
⛔ Files ignored due to path filters (2)
ios/Podfile.lockis excluded by!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (3)
app.jsonapp/AppContainer.tsxpackage.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ESLint and Test / run-eslint-and-test
- GitHub Check: format
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-02-05T13:55:00.974Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6930
File: package.json:101-101
Timestamp: 2026-02-05T13:55:00.974Z
Learning: In this repository, the dependency on react-native-image-crop-picker should reference the RocketChat fork (RocketChat/react-native-image-crop-picker) with explicit commit pins, not the upstream ivpusic/react-native-image-crop-picker. Update package.json dependencies (and any lockfile) to point to the fork URL and a specific commit, ensuring edge-to-edge Android fixes are included. This pattern should apply to all package.json files in the repo that declare this dependency.
Applied to files:
package.json
📚 Learning: 2026-02-05T13:55:06.688Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6930
File: package.json:101-101
Timestamp: 2026-02-05T13:55:06.688Z
Learning: The RocketChat/Rocket.Chat.ReactNative repository uses a fork of react-native-image-crop-picker (RocketChat/react-native-image-crop-picker) with custom Android edge-to-edge fixes, not the upstream ivpusic/react-native-image-crop-picker package. Dependencies should reference commit pins from the RocketChat fork.
Applied to files:
app.json
📚 Learning: 2026-03-10T15:21:45.098Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7046
File: app/containers/InAppNotification/NotifierComponent.stories.tsx:46-75
Timestamp: 2026-03-10T15:21:45.098Z
Learning: In `app/containers/InAppNotification/NotifierComponent.tsx` (React Native, Rocket.Chat), `NotifierComponent` is exported as a Redux-connected component via `connect(mapStateToProps)`. The `isMasterDetail` prop is automatically injected from `state.app.isMasterDetail` and does not need to be passed explicitly at call sites or in Storybook stories that use the default (connected) export.
Applied to files:
app/AppContainer.tsx
🔇 Additional comments (5)
app.json (1)
2-5: LGTM!The
expo-fontplugin is correctly added to enable native font loading support, which is required for theuseFontshook inAppContainer.tsx.app/AppContainer.tsx (3)
47-59: LGTM! The font loading guard logic is correct.The implementation properly follows the idiomatic Expo pattern:
- Waits for fonts to load OR error before proceeding
- Maintains the
rootinvariant to prevent rendering with empty navigation state- Logs font errors without blocking the app indefinitely
5-5: LGTM!The imports are correctly updated to support the new font loading functionality.
Also applies to: 20-20
47-49: The custom font file is already present at the specified path.The file
app/static/fonts/custom.ttfexists in the repository, so the font loading will proceed without errors. No action needed.package.json (1)
68-68: No compatibility issue. The versionexpo-font@~13.3.2is the expected version for Expo SDK 53 and is fully compatible.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app.json`:
- Around line 2-3: The app.json currently lists "expo-font" in the "plugins"
array but that declaration is ineffective because this repo uses the bare React
Native build workflow invoked via npx react-native run-ios / npx react-native
run-android (which bypasses expo prebuild); either remove the unused "expo-font"
entry from the "plugins" array in app.json, or migrate the build workflow to use
expo prebuild / EAS Build so the "expo-font" plugin is applied during native
generation and font preloading works as expected.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 37c950fa-9d03-4296-a10a-292d7ab03c5a
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (3)
app.jsonpackage.jsontsconfig.json
✅ Files skipped from review due to trivial changes (1)
- tsconfig.json
📜 Review details
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-02-05T13:55:00.974Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6930
File: package.json:101-101
Timestamp: 2026-02-05T13:55:00.974Z
Learning: In this repository, the dependency on react-native-image-crop-picker should reference the RocketChat fork (RocketChat/react-native-image-crop-picker) with explicit commit pins, not the upstream ivpusic/react-native-image-crop-picker. Update package.json dependencies (and any lockfile) to point to the fork URL and a specific commit, ensuring edge-to-edge Android fixes are included. This pattern should apply to all package.json files in the repo that declare this dependency.
Applied to files:
package.json
📚 Learning: 2026-02-05T13:55:06.688Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6930
File: package.json:101-101
Timestamp: 2026-02-05T13:55:06.688Z
Learning: The RocketChat/Rocket.Chat.ReactNative repository uses a fork of react-native-image-crop-picker (RocketChat/react-native-image-crop-picker) with custom Android edge-to-edge fixes, not the upstream ivpusic/react-native-image-crop-picker package. Dependencies should reference commit pins from the RocketChat fork.
Applied to files:
app.json
🔇 Additional comments (1)
package.json (1)
67-67: Lockfile properly captures the newexpo-fontdependency with exact resolution.The dependency is correctly recorded in yarn.lock at version 13.3.2 with its integrity hash, ensuring deterministic installs across CI and local environments.
| "name": "RocketChatRN", | ||
| "plugins": ["expo-font"] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Expect: plugin is declared in app config.
rg -n '"plugins"\s*:\s*\[.*"expo-font".*\]' app.json -C2
fd -HI 'app.json|app.config.js|app.config.ts|app.config.mjs|app.config.cjs'
# Expect: some workflow reference to Expo config/prebuild if plugin effects are required at build-time.
rg -n 'expo prebuild|expo config|eas build|expo run:android|expo run:ios' package.json -C2Repository: RocketChat/Rocket.Chat.ReactNative
Length of output: 149
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check package.json for build scripts and Expo/EAS references
echo "=== package.json content ==="
cat package.json | head -100
# Check for EAS build configuration
echo -e "\n=== Checking for eas.json ==="
find . -name "eas.json" -type f 2>/dev/null || echo "No eas.json found"
# Check for native directories
echo -e "\n=== Checking for native directories ==="
ls -la | grep -E '^d.*\s(ios|android)$' || echo "No ios/android directories"
# Check app.json more thoroughly
echo -e "\n=== Full app.json content ==="
cat app.jsonRepository: RocketChat/Rocket.Chat.ReactNative
Length of output: 4406
The expo-font plugin declaration in app.json has no effect with the current build workflow.
The project uses npx react-native run-ios and npx react-native run-android commands to build (bare React Native workflow with native directories). Expo plugins only apply when using expo prebuild or eas build. Since the native build path bypasses the Expo prebuild system entirely, the plugin configuration in app.json is never executed. Either remove the unused plugin declaration from app.json, or switch the build workflow to use Expo prebuild/EAS Build if font preloading is needed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app.json` around lines 2 - 3, The app.json currently lists "expo-font" in the
"plugins" array but that declaration is ineffective because this repo uses the
bare React Native build workflow invoked via npx react-native run-ios / npx
react-native run-android (which bypasses expo prebuild); either remove the
unused "expo-font" entry from the "plugins" array in app.json, or migrate the
build workflow to use expo prebuild / EAS Build so the "expo-font" plugin is
applied during native generation and font preloading works as expected.
Proposed changes
On older Android devices, vector icons are not displayed because Expo fails to load the font.
Issue(s)
https://rocketchat.atlassian.net/browse/SUP-977
How to test or reproduce
Screenshots
Types of changes
Checklist
Further comments
Summary by CodeRabbit
New Features
Bug Fixes
Chores